using System;
using TestCases.CompareAssert.Core.Builders;
using TestCases.CompareAssert.Core.Comparers.Interfaces;
using TestCases.CompareAssert.Core.Interfaces;

namespace TestCases.CompareAssert.Core.Comparers.Basic
{

    public enum SetupStatus
    {
        Disable,
        Escape,
        Default 
    }

    public delegate SetupStatus SetupDelegate<TComparer>(TComparer comparer, ICompareContext context);
    
    public class SetupComparer<TComparer>: IObjectComparer where TComparer: IObjectComparer
    {
        private readonly SetupDelegate<TComparer> _setupDelegate;
        private readonly TComparer _comparer;

        public SetupComparer(SetupDelegate<TComparer> setupDelegate, TComparer comparer)
        {
            _setupDelegate = setupDelegate;
            _comparer = comparer;
        }                                                                                                                                                                                                                                                          

        public string Name
        {
            get { return _comparer.Name; }
        }

        public IResultBuilder Compare(ICompareContext context)
        {
            switch (_setupDelegate(_comparer, context))
            {
                case SetupStatus.Disable:
                    return this.IsNotApplicable(context).
                        Message("<{LPath}> cannot be compared with <{RPath}> because comparer is disabled.").
                        With(new {Comparer = _comparer.Name});                    

                case SetupStatus.Escape:
                    return _comparer.Compare(context).TryChangeStatus(CompareStatus.NotEquals, CompareStatus.NotApplicable);

                case SetupStatus.Default:
                    return _comparer.Compare(context);
                    
                default: 
                    throw new ApplicationException("Illegal SetupStatus.");
            }            
        }
    }
    
    public class SetupComparer: SetupComparer<IObjectComparer>
    {
        public SetupComparer(SetupDelegate<IObjectComparer> setupPredicate, IObjectComparer comparer) : base(setupPredicate, comparer)
        {
        }
    }
}